package com.avcompris.util;

import static com.avcompris.util.ExceptionUtils.nonNullArgument;
import static java.util.Locale.ENGLISH;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import com.avcompris.common.annotation.ThreadSafe;

/**
 * Provide date utilities ans date patterns.
 * 
 * @author David Andriana Copyright Avantage Compris SARL 2008-2009 ©
 */
public abstract class DateUtils extends AbstractUtils {

	/**
	 * the ISO-8601 standard format for dates in XML contents: "
	 * <tt>yyyy-MM-dd'T'HH:mm:ss.SSSZ</tt>".
	 */
	public static final String DATETIME_PATTERN_COLON_MS_Z = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

	/**
	 * Some other non-standard format for dates in XML contents: "
	 * <tt>yyyy-MM-dd-HHmmss</tt>".
	 */
	public static final String DATETIME_PATTERN_NOCOLON_NOMS_NOZ = "yyyy-MM-dd-HHmmss";

	/**
	 * the ISO-8601 standard format for dates in XML contents: "
	 * <tt>yyyy-MM-dd'T'HH:mm:ssZ</tt>".
	 */
	public static final String DATETIME_PATTERN_COLON_NOMS_Z = "yyyy-MM-dd'T'HH:mm:ss'Z'";

	/**
	 * the ISO-8601 standard format for dates in XML contents: "
	 * <tt>yyyy-MM-dd'T'HHmmss.SSSZ</tt>".
	 */
	public static final String DATETIME_PATTERN_NOCOLON_MS_Z = "yyyy-MM-dd'T'HHmmss.SSS'Z'";

	/**
	 * the ISO-8601 standard format for dates in XML contents: "
	 * <tt>yyyy-MM-dd'T'HHmmssZ</tt>".
	 */
	public static final String DATETIME_PATTERN_NOCOLON_NOMS_Z = "yyyy-MM-dd'T'HHmmss'Z'";

	/**
	 * the formatter that uses {@link #DATETIME_PATTERN_COLON_MS_Z}.
	 */
	@ThreadSafe
	public static final DateTimeFormatter DATETIMEFORMATTER_COLON_MS_Z = DateTimeFormat
			.forPattern(DATETIME_PATTERN_COLON_MS_Z).withLocale(ENGLISH);

	/**
	 * the formatter that uses {@link #DATETIME_PATTERN_NOCOLON_NOMS_NOZ}.
	 */
	@ThreadSafe
	public static final DateTimeFormatter DATETIMEFORMATTER_NOCOLON_NOMS_NOZ = DateTimeFormat
			.forPattern(DATETIME_PATTERN_NOCOLON_NOMS_NOZ).withLocale(ENGLISH);

	/**
	 * the formatter that uses {@link #DATETIME_PATTERN_COLON_NOMS_Z}.
	 */
	@ThreadSafe
	public static final DateTimeFormatter DATETIMEFORMATTER_COLON_NOMS_Z = DateTimeFormat
			.forPattern(DATETIME_PATTERN_COLON_NOMS_Z).withLocale(ENGLISH);

	/**
	 * the formatter that uses {@link #DATETIME_PATTERN_NOCOLON_MS_Z}.
	 */
	@ThreadSafe
	public static final DateTimeFormatter DATETIMEFORMATTER_NOCOLON_MS_Z = DateTimeFormat
			.forPattern(DATETIME_PATTERN_NOCOLON_MS_Z).withLocale(ENGLISH);

	/**
	 * the formatter that uses {@link #DATETIME_PATTERN_NOCOLON_NOMS_Z}.
	 */
	@ThreadSafe
	public static final DateTimeFormatter DATETIMEFORMATTER_NOCOLON_NOMS_Z = DateTimeFormat
			.forPattern(DATETIME_PATTERN_NOCOLON_NOMS_Z).withLocale(ENGLISH);

	/**
	 * Parses the date.
	 * 
	 * @param stringDate the string date
	 * @return the date time
	 */
	@ThreadSafe
	public static DateTime parseDateTime(
			final String stringDate) {

		nonNullArgument(stringDate, "stringDate");

		final DateTimeFormatter formatter;

		final int length = stringDate.length();

		if (length == DATETIME_PATTERN_NOCOLON_NOMS_NOZ.length()) {

			formatter = DATETIMEFORMATTER_NOCOLON_NOMS_NOZ;

		} else {

			if (!stringDate.endsWith("Z")) {
				throw new IllegalArgumentException(
						"DateTime String should end with \"Z\": " + stringDate);
			}

			if (stringDate.contains(":")) {

				if (length == DATETIME_PATTERN_COLON_MS_Z.length() - 4) {

					formatter = DATETIMEFORMATTER_COLON_MS_Z;

				} else {

					formatter = DATETIMEFORMATTER_COLON_NOMS_Z;
				}

			} else {

				if (length == DATETIME_PATTERN_NOCOLON_MS_Z.length() - 4) {

					formatter = DATETIMEFORMATTER_NOCOLON_MS_Z;

				} else {

					formatter = DATETIMEFORMATTER_NOCOLON_NOMS_Z;
				}
			}
		}

		final DateTime dateTime = formatter.parseDateTime(stringDate);

		return dateTime;
	}

}
